#ifndef FUNCTIONS_H
#define FUNCTIONS_H

#include <boost/spirit/include/phoenix_function.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include "big_int.h"

#include "user_function.h"

namespace functions
{
   struct big_int_from_str_im
   {
      template<typename A>
      struct result
      {
         typedef big_int type;
      };

      template<typename A>
      big_int operator()(A s) const
      {
         return big_int(s);
      }
   };

   struct pow_im
   {
      template<typename A, typename B>
      struct result
      {
         typedef big_int type;
      };

      template<typename A, typename B>
      big_int power(const A& a, const B& b) const
      {
         if (b == 0)
            return 1;

         A res = power(a, b / 2);

         if (b % 2 == 1) 
            return res * res * a;

         return res * res;
      }
      
      template<typename A, typename B>
      big_int operator()(const A& a, const B& b) const
      {
         return power(a, b);
      }
   };
   
   struct user_function_im
   {
      template<typename A, typename B>
      struct result
      {
         typedef big_int type;
      };
      
      template<typename A, typename B>
      B operator()(A a, B b) const
      {
         return get_function()[a](b);
      }
   };
}

boost::phoenix::function<functions::big_int_from_str_im>& big_int_from_string();
boost::phoenix::function<functions::pow_im>& pow();
boost::phoenix::function<functions::user_function_im>& user_function();

#endif
